using System;
using System.Reflection;
using System.Collections.Generic;
using System.Text;

namespace Open.Data.Persistence.Hashes
{
    //Base abstract class containing parent labels and overriding the hashcode logic
    public abstract class LabelHash
    {
        private List<LabelHash> _parents;
        private LabelHash _parent;

        //Constructors
        public LabelHash()
        {
            _parents = new List<LabelHash>();
        }

        public LabelHash(LabelHash parent)
        {
            _parent = parent;
            _parents = parent.CopyParents();
            _parents.Add(parent);
        }
        
        //Properties
        public List<LabelHash> Parents
        {
            get
            {
                return _parents;
            }
            set
            {
                _parents = value;
            }
        }

        public LabelHash Parent
        {
            get
            {
                return _parent;
            }
        }

        //Methods
        public override bool Equals(object obj)
        {
            return (GetHashCode() == obj.GetHashCode());
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        //Implementation
        protected internal List<LabelHash> CopyParents()
        {
            List<LabelHash> parents = new List<LabelHash>(Parents.Count);

            foreach (LabelHash label in Parents)
            {
                parents.Add(label);
            }

            return parents;
        }
    }

    //Abstract class implementing the current item as a generic type
    public abstract class LabelHash<T>: LabelHash
    {
        //Property variables
        private T _item; 
        
        //Constructors
        public LabelHash(T item)
        {
            Item = item;
            
        }

        public LabelHash(T item, LabelHash parent): base(parent)
        {
            Item = item;
        }

        //Properties
        public T Item
        {
            get
            {
                return _item;
            }
            set
            {
                _item = value;
            }
        }
        
        //Methods
        public override int GetHashCode()
        {
            //Create a stringbuilder and add strings of all parent labels in the correct order
            StringBuilder builder = new StringBuilder();
            foreach (LabelHash label in Parents)
            {
                builder.Append(label.ToString()); //Use string to avoid recursing this sub
            }

            //Add the item hash
            builder.Append(Item.ToString().GetHashCode()); //Must use string to avoid overriding this sub

            return builder.ToString().GetHashCode();
        }
    }
}
